package com.xiezc.springboot_dht.message;

import com.xiezc.springboot_dht.model.BeMap;
import com.xiezc.springboot_dht.model.BeObject;
import com.xiezc.springboot_dht.model.BeString;
import com.xiezc.springboot_dht.util.BeException;
import com.xiezc.springboot_dht.util.Const;
import com.xiezc.springboot_dht.util.XUtil;

import java.net.InetSocketAddress;
import java.util.Set;

import static com.xiezc.springboot_dht.message.MessageBuild.*;

public class ReqMsgBuild {
    BeMap beMap;
    BeMap a = new BeMap();

    public ReqMsgBuild(BeMap beMap) {
        this.beMap = beMap;
    }

    public ReqMsgBuild buildQ(MsgTypeEnum str) {
        switch (str) {
            case ping:
                beMap.put(q, new BeString(str.getVal()));
                break;
            case findNode:
                beMap.put(q, new BeString(str.getVal()));
                break;
            case getPeers:
                beMap.put(q, new BeString(str.getVal()));
                break;
            case annountcePeer:
                beMap.put(q, new BeString(str.getVal()));
                break;
            case resp_ping:
                break;
            case resp_findNode:
                break;
            case resp_getPeers:
                break;
            default:
                break;
        }
        return this;
    }

    public ReqMsgBuild buildAId(String id) {
        a.put(MessageBuild.id, new BeString(id));
        return this;
    }
    public ReqMsgBuild buildAId(BeString id) {
        a.put(MessageBuild.id, id);
        return this;
    }
    public ReqMsgBuild buildAInfoHash(String infoHash) {
        a.put(info_hash, new BeString(infoHash));
        return this;
    }

    public ReqMsgBuild buildATarget(BeString target) {
        a.put(MessageBuild.target, target);
        return this;
    }

    public ReqMsgBuild buildAImpliedPort(String target) {
        a.put(implied_port, new BeString(target));
        return this;
    }

    public ReqMsgBuild buildAPort(String port) {
        a.put(MessageBuild.port, new BeString(port));
        return this;
    }

    public ReqMsgBuild buildAToken(String target) {
        a.put(token, new BeString(target));
        return this;
    }

    public ReqMsgBuild buildT(String target) {
        beMap.put(t, new BeString(target));
        return this;
    }

    public Message buildPing(InetSocketAddress socketAddress) {

        Set<BeObject> keySet = beMap.getValue().keySet();

        if (!keySet.contains(t)) {
            beMap.put(t, new BeString("p" + XUtil.getRandomChar()));
        }
        if (!keySet.contains(y)) {

            beMap.put(y, q);
        }
        if (!keySet.contains(q)) {
            buildQ(MsgTypeEnum.ping);
        }
        if (!keySet.contains(MessageBuild.a)) {
            beMap.put(MessageBuild.a, a);
        }
        if (!a.getValue().keySet().contains(id)) {
            throw new BeException("a中的id的值未设置");
        }

        Message message = new Message();
        message.setBeMap(beMap);
        message.setMsgTypeEnum(MsgTypeEnum.ping);
        message.setSocketAddress(socketAddress);
        return message;
    }

    public Message buildPing(String ip, int port) {
        return buildPing(new InetSocketAddress(ip, port));
    }

    public Message buildGetPeers(String ip, int port) {
        return buildGetPeers(new InetSocketAddress(ip, port));
    }

    public Message buildGetPeers(InetSocketAddress socketAddress) {
        beMap.put(MessageBuild.a, a);

        Set<BeObject> keySet = beMap.getValue().keySet();

        if (!keySet.contains(MessageBuild.t)) {
            beMap.put(t, new BeString("g" + XUtil.getRandomChar()));

        }
        if (!keySet.contains(y)) {
            throw new BeException("y的值未设置");
        }
        if (!keySet.contains(q)) {
            throw new BeException("q的值未设置");
        }
        if (!keySet.contains(MessageBuild.a)) {
            throw new BeException("a的值未设置");
        }
        if (!a.getValue().keySet().contains(id)) {
            throw new BeException("a中的id的值未设置");
        }
        if (!a.getValue().keySet().contains(info_hash)) {
            throw new BeException("a中的info_hash的值未设置");
        }

        Message message = new Message();
        message.setBeMap(beMap);
        message.setMsgTypeEnum(MsgTypeEnum.getPeers);
        message.setSocketAddress(socketAddress);
        return message;
    }

    public Message buildAnnouncePeer(String ip, int port) {
        return buildAnnouncePeer(new InetSocketAddress(ip, port));
    }

    public Message buildAnnouncePeer(InetSocketAddress socketAddress) {
        beMap.put(MessageBuild.a, a);

        Set<BeObject> keySet = beMap.getValue().keySet();

        if (!keySet.contains(t)) {
            beMap.put(t, new BeString("a" + XUtil.getRandomChar()));
        }
        if (!keySet.contains(y)) {
            throw new BeException("y的值未设置");
        }
        if (!keySet.contains(q)) {
            throw new BeException("q的值未设置");
        }
        if (!keySet.contains(MessageBuild.a)) {
            throw new BeException("a的值未设置");
        }
        if (!a.getValue().keySet().contains(id)) {
            throw new BeException("a中的id的值未设置");
        }
        if (!a.getValue().keySet().contains(implied_port)) {
            throw new BeException("a中的implied_port的值未设置");
        }
        if (!a.getValue().keySet().contains(info_hash)) {
            throw new BeException("a中的info_hash的值未设置");
        }
        if (!a.getValue().keySet().contains(port)) {
            throw new BeException("a中的port的值未设置");
        }
        if (!a.getValue().keySet().contains(token)) {
            throw new BeException("a中的token的值未设置");
        }
        Message message = new Message();
        message.setBeMap(beMap);
        message.setMsgTypeEnum(MsgTypeEnum.annountcePeer);
        message.setSocketAddress(socketAddress);
        return message;
    }

    public Message buildFindNode(String ip, int port) {
        return buildFindNode(new InetSocketAddress(ip, port));
    }

    public Message buildFindNode(InetSocketAddress socketAddress) {
        beMap.put(MessageBuild.a, a);

        Set<BeObject> keySet = beMap.getValue().keySet();

        if (!keySet.contains(t)) {
            beMap.put(t, new BeString("f" + XUtil.getRandomChar()));
        }
        if (!keySet.contains(y)) {
            beMap.put(y, q);
        }
        if (!keySet.contains(q)) {
            beMap.put(q, find_node);
        }
        if (!keySet.contains(MessageBuild.a)) {
            throw new BeException("a的值未设置");
        }
        if (!a.getValue().keySet().contains(id)) {
            a.put(id, Const.thisId);
        }
        if (!a.getValue().keySet().contains(target)) {
            throw new BeException("a中的target的值未设置");
        }

        Message message = new Message();
        message.setBeMap(beMap);
        message.setMsgTypeEnum(MsgTypeEnum.findNode);
        message.setSocketAddress(socketAddress);
        return message;
    }

}

